/***************************************************************
*   File name    :  SHT20.c  
*   Description  :  SHT20 Humidity and Temperature Sensors 
*     M C U      :  STC89C52RC
*   Compiler     :  Keil uVision V4.00a (C51)
*   Created by   :  dingshidong
*   Copyright    :  Copyright(c) https://wclh.taobao.com/   
*   Created data :  2015.05.08  
*   Vision       :  V1.0
*****************************************************************/
#include "bsp_SHT20.h"
#include "bsp_BL55072A.h"
#include "softwareMultiTimer.h"

//#define TEST_TEMP_LCD_DIS
/*================================================================
【  Name  】Pin Description
【Function】模拟IIC使用的引脚定义，注意要上拉电阻，SDA和SCL均上拉10KΩ电阻
【  Notes 】
================================================================*/
static MultiTimer tempHumiDelayTime = {.Handle = 0xFF10};
static bool isStartReadTempHumi = true;
static bool isDelayTimeExpierd = false;
//EN_LP_HARD_TIMER_EM3_SYS_RTC_1
static int16_t s_iCurrentTemp = 200; //实际值*10，20℃
static int16_t s_iCurrentHumi = 500 ; //实际值*10

static int16_t sLCD_Temp_get_former =0;
static int16_t sLCD_Humi_get_former =0;

enum READ_SHT_STATE_E
{
  READ_SHT_STATE_IDLE = 0,
  READ_SHT_STATE_WAIT_WAKE_UP,
  READ_SHT_STATE_WAIT_FINISH
};
static uint8_t s_readShtState = 0;

/*************Pin Description*************
 */

static ds_gpio_t SCLGpio =
    {
        .port = gpioPortC,
        .pin = 2,
        .mode = gpioModePushPull,
        .initial = 0,
        .valid = 1,
    };

static ds_gpio_t SDAGpio =
    {
        .port = gpioPortC,
        .pin = 3,
        .mode = gpioModeInput,
        .initial = 0,
        .valid = 1,
    };


/* 定义读写SCL和SDA的宏 */
#define I2C_SCL_1()  ds_gpio_set(&SCLGpio)        /* SCL = 1 */ //PC2
#define I2C_SCL_0()  ds_gpio_clear(&SCLGpio)      /* SCL = 0 */

#define I2C_SDA_1()  ds_gpio_set(&SDAGpio)      /* SDA = 1 */ //PC3
#define I2C_SDA_0()  ds_gpio_clear(&SDAGpio)    /* SDA = 0 */

#define I2C_SDA_READ()  ds_gpio_read(&SDAGpio)  /* 读SDA口线状态 */
//#define I2C_SCL_READ()  ds_gpio_read()  /* 读SCL口线状态 */

/* 切换GPIO输入/输出 */
#define I2C_SDA_IN()  {SDAGpio.mode = gpioModeInput; ds_gpio_init(&SDAGpio);}
#define I2C_SDA_OUT() //每次输出均修改模式，无需提前修改输出模式 /*推挽输出*/


#define SDA_IN() I2C_SDA_IN()
#define SDA_OUT() I2C_SDA_OUT()

/*================================================================
【  Name  】
【Function】SHT20的I2C地址
【  Notes 】
================================================================*/
#define SHT20ADDR 0x80
/*================================================================
【  Name  】
【Function】应答位电平定义
【  Notes 】
================================================================*/
#define ACK           0            //应答信号
#define NACK        1             //非应答信号

uint8_t getTempHumiWorkState()
{
  return ( (s_readShtState == READ_SHT_STATE_IDLE &&  isStartReadTempHumi) || isDelayTimeExpierd);
}

int16_t getCurrentHumi()
{
  return s_iCurrentHumi;
}

int16_t getCurrentTemp()
{
  return s_iCurrentTemp;
}

void readShtDelayTimeCallback(struct MultiTimerHandle* timeHandle,void* pData)
{
  (void) timeHandle;
  (void) pData;
  isDelayTimeExpierd = true;
}

void nextReadDelayTimeCallback(struct MultiTimerHandle* timeHandle,void* pData)
{
  (void) timeHandle;
  (void) pData;
  startReadTempHumi();
}
/*================================================================
【  Name  】void I2CDelay()
【Function】delay Nms
【  Notes 】
================================================================*/
void I2CDelay(void)
{
    uchar i;
    for(i=0;i<1;i++)
    {

    }
}
/*------------------------------------------------------------*/
/**********************Simulation I2C Function*****************/
/*------------------------------------------------------------*/

/*================================================================
【  Name  】void I2CStart(void)
【Function】I2C起始信号
【  Notes 】SCL、SDA同为高，SDA跳变成低之后，SCL跳变成低          
================================================================*/
void I2CStart(void)
{        
     I2C_SDA_1();//SDA = 1;                            //发送起始条件的数据信号--ZLG
     I2C_SCL_1();//SCL = 1;
     I2CDelay();                    //起始条件建立时间大于4.7us,延时--ZLG
     I2C_SDA_0();//SDA = 0;                            //发送起始信号-ZLG
     I2CDelay();                    //起始条件锁定时间大于4μs--ZLG
     I2C_SCL_0();//SCL = 0;                            //钳住I2C总线，准备发送或接收数据--ZLG
    I2CDelay();
}
/*================================================================
【  Name  】void I2CStop(void)
【Function】I2C停止信号
【  Notes 】SCL、SDA同为低，SCL跳变成高之后，SDA跳变成高           
================================================================*/
void I2CStop(void)
{        
    I2C_SDA_0();//SDA = 0;                        //发送结束条件的数据信号--ZLG
    I2C_SCL_1();//SCL = 1;               //发送结束条件的时钟信号--ZLG
    I2CDelay();                //结束条件建立时间大于4μs--ZLG
    I2C_SDA_1();//SDA = 1;                        //发送I2C总线结束信号--ZLG
    I2CDelay();
}

/*================================================================
【  Name  】uchar I2C_Write_Byte(uchar WRByte)
【Function】I2C写一个字节数据，返回ACK或者NACK
【  Notes 】从高到低，依次发送
================================================================*/
uchar I2C_Write_Byte(uchar Write_Byte)         //Sendbyte
{
    uchar i,re;
    for(i=0;i<8;i++)              //要传送的数据长度为8位--ZLG
    {
      if(Write_Byte&0x80)              //判断发送位--ZLG
      {
          I2C_SDA_1();//SDA = 1;
      }
      else
      {
          I2C_SDA_0();//SDA = 0;
      }
      I2CDelay();
      I2C_SCL_1();//SCL=1;                                  //输出SDA稳定后，拉高SCL给出上升沿，从机检测到后进行数据采样
      I2CDelay();                        //保证时钟高电平周期大于4μs--ZLG
      I2C_SCL_0();//SCL=0;
      if (i == 7)
    {
      I2C_SDA_1();//SDA = 1; // 释放总线
    }
      Write_Byte <<= 1;
    }
    I2CDelay();
                                     //8位发送完后释放数据线，准备接收应答位-ZLG
   SDA_IN();
   I2CDelay();
   I2C_SCL_1();//SCL = 1;                      //MCU告知SHT2X数据发送完毕，等待从机的应答信号

   I2CDelay();
    /*以下是判断I2C总线接收应到应答信号是ACK还是NACK*/
    if(I2C_SDA_READ() == 1)//SDA==1)  			//SDA为高，收到NACK
		{
			re=NACK;   
		}
    else  			//SDA为低，收到ACK
		{
			
			re=ACK;  
		}
		
    I2C_SCL_0();//SCL=0;
    SDA_OUT();
    I2CDelay();
    //printf("+%d\r\n",re);
		return re;
}

/*================================================================
【  Name  】uchar I2C_Read_Byte(uchar AckValue)
【Function】I2C读一个字节数据，入口参数用于控制应答状态，ACK或者NACK
【  Notes 】从高到低，依次接收
================================================================*/
uchar I2C_Read_Byte(uchar AckValue)//receivebyte
{
  uchar i,RDByte=0;
                                                 //置时钟线为低，准备接收数据位--ZLG
  I2C_SDA_1();//SDA = 1;  		//释放总线,置数据线为输入方式--ZLG
  SDA_IN();
  for (i=0;i<8;i++)
  {
    RDByte <<= 1;                  //移位
    I2C_SCL_1();//SCL = 1;                          //SCL高电平期间，采集SDA信号，并作为有效数据 //置时钟线为高使数据线上数据有效--ZLG
    I2CDelay();
    if(I2C_SDA_READ())//SDA)                           //采样获取数据
    {
       RDByte++;
    }
    I2C_SCL_0();//SCL = 0;
    I2CDelay();
                                    //下降沿，从机给出下一位值
  }
  SDA_OUT();
  /*以下是I2C总线发送应答信号ACK或者NACK*/
  if(AckValue) //SDA = AckValue; //应答状态
  I2C_SDA_1();
  else
  I2C_SDA_0();

  I2C_SDA_0();//SDA=0;
  I2CDelay();
  I2C_SCL_1();//SCL = 1;
  I2CDelay();                  //时钟低电平周期大于4μs--ZLG
  I2C_SCL_0();//SCL = 0;                                  //清时钟线，钳住I2C总线以便继续接收--ZLG
  I2CDelay();
  I2C_SDA_1();//SDA = 1;
  return RDByte;
}

uint8 SHTC3_CRC_CHECK(uint16 DAT,uint8 CRC_DAT)
{
    uint8 i,t,ret;
    uint8 CRC_BYTE;

    CRC_BYTE = 0xFF;
    ret = (DAT>>8) & 0xFF;

    for(t = 0;t < 2;t ++)
    {
        CRC_BYTE ^= ret;
        for(i = 0;i < 8;i ++)
        {
            if(CRC_BYTE & 0x80)
            {
                CRC_BYTE <<= 1;

                CRC_BYTE ^= 0x31;
            }
            else
            {
                CRC_BYTE <<= 1;
            }
        }

        if(t == 0)
        {
            ret = DAT & 0xFF;
        }
    }

    if(CRC_BYTE == CRC_DAT)
    {
        ret = 1;
    }
    else
    {
        ret = 0;
    }

    return ret;
}

void startReadTempHumi()
{
  isStartReadTempHumi = true;
}

void ReadShtC3(void)
{
	uint8   i;
	uint8   Cnt1 = 0;
	uint8   buf[6]={0,0};
	uint32_t MEASUREMENT = 0;

	switch (s_readShtState)
	{
	  case READ_SHT_STATE_IDLE:

	  if(!isStartReadTempHumi)
	     break;
	  isStartReadTempHumi = false;
    I2CStart();                       //start I2C
    I2C_Write_Byte(SHTc3_I2C_ADR_W);
    I2C_Write_Byte(SHTc3_WakeUp_H);
    I2C_Write_Byte(SHTc3_WakeUp_L);
    I2CStop();//IIC管脚 上拉省电

    isDelayTimeExpierd = true;//轮询即可
    s_readShtState = READ_SHT_STATE_WAIT_WAKE_UP;
	  break;

	  case READ_SHT_STATE_WAIT_WAKE_UP:

	  if(!isDelayTimeExpierd)//等待上一次延时结束
      break;
	  isDelayTimeExpierd = false;
    I2CStart();
    I2C_Write_Byte(SHTc3_I2C_ADR_W);
    I2C_Write_Byte(0x58);
    I2C_Write_Byte(0xe0);//无需clockStretching， Humi先
    I2CStop();//IIC管脚 上拉省电
    isDelayTimeExpierd = false;
    //手册上标的是不超过20ms
    softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&tempHumiDelayTime,426, readShtDelayTimeCallback, NULL ,1);//按手册，延时13ms； 进入该状态时 打开定时器计超时
    s_readShtState = READ_SHT_STATE_WAIT_FINISH;
    break;

	  case READ_SHT_STATE_WAIT_FINISH:

    if(!isDelayTimeExpierd)//等待上一次延时结束
      break;
    isDelayTimeExpierd = false;

    I2CStart();
    if(I2C_Write_Byte(SHTc3_I2C_ADR_W|0x01)==0)
    {
      for(i=0;i<6;i++)
      {
        buf[i]=I2C_Read_Byte(ACK);
      }
      I2CStop();

      MEASUREMENT = buf[0];
      MEASUREMENT <<= 8;
      MEASUREMENT |= buf[1];

      Cnt1 = SHTC3_CRC_CHECK(MEASUREMENT,buf[2]);
      if(Cnt1 == 1)
      {
        s_iCurrentHumi = (int16_t)( (MEASUREMENT*1000) >> 16); //修改，湿度取小数点后1位， 乘10扩为整型
      }

      MEASUREMENT = buf[3];
      MEASUREMENT <<= 8;
      MEASUREMENT |= buf[4];
      Cnt1 = SHTC3_CRC_CHECK(MEASUREMENT,buf[5]);
      if(Cnt1 == 1)
      {
        s_iCurrentTemp = (int16_t)( (MEASUREMENT*1750) >> 16) - (int16_t)450;//修改，温度*10
      }
//      static int16_t testTemp = -301;
//      s_iCurrentTemp = testTemp;
//      testTemp += 5;

      if(sLCD_Temp_get_former!=s_iCurrentTemp)
      {
        LCD_DIS_Flag=1;
        sLCD_Temp_get_former=s_iCurrentTemp;
      }

      if(sLCD_Humi_get_former!=s_iCurrentHumi)
      {
        LCD_DIS_Flag=1;
        sLCD_Humi_get_former=s_iCurrentHumi;
      }
    }
    else
    {
        I2CStop();
    }

    I2CStart();                      //start I2C
    I2C_Write_Byte(SHTc3_I2C_ADR_W);
    I2C_Write_Byte(0xb0);
    I2C_Write_Byte(0x98);
    I2CStop();
    //2s后开启下一次温湿度采样
    softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&tempHumiDelayTime,65536, nextReadDelayTimeCallback, NULL ,1);//若应用层在该定时器溢出前 唤醒并调用startReadTempHumi()，则该定时器会被重复覆盖
    s_readShtState = READ_SHT_STATE_IDLE;
    break;
	}
}

